<?php
/**
 * SocialEngine
 *
 * @category   Application_Extensions
 * @package    Inviter
 * @copyright  Copyright Hire-Experts LLC
 * @license    http://www.hire-experts.com
 * @version    $Id: Provider.php 2010-07-02 19:54 mirlan $
 * @author     Mirlan
 */

/**
 * @category   Application_Extensions
 * @package    Inviter
 * @copyright  Copyright Hire-Experts LLC
 * @license    http://www.hire-experts.com
 */

class Inviter_Api_Provider extends Core_Api_Abstract {
	/**
	 * @var Facebook_Api
	 */
	public static $fb_instance;
	
	public static $fb_user_id;
	
	public static function getFBInstance() {
		$settings = Engine_Api::_ ()->getApi ( 'settings', 'core' );
		
		if (self::$fb_instance === null) {
			self::$fb_instance = new Inviter_Api_Facebook ( array ('appId' => $settings->getSetting ( 'inviter.facebook.consumer.key', false ), 'secret' => $settings->getSetting ( 'inviter.facebook.consumer.secret', false ), 'cookie' => true, 'baseDomain' => $_SERVER ['HTTP_HOST'] ) );
		}
		
		return self::$fb_instance;
	}
	
	public static function getFBUserId() {
		if (self::$fb_user_id !== null) {
			return self::$fb_user_id;
		}
		
		$facebook = self::getFBInstance ();
		if (! $facebook) {
			self::$fb_user_id = 0;
		} else {
			try {
				self::$fb_user_id = $facebook->getUser ();
			} catch ( Exception $e ) {
				self::$fb_user_id = 0;
			}
		}
		
		return self::$fb_user_id;
	}
	
	public function getProviderConfig($provider) {
		$config = array ();
		$settings = Engine_Api::_ ()->getApi ( 'settings', 'core' );
		$host_url = (_ENGINE_SSL ? 'https://' : 'http://') . $_SERVER ['HTTP_HOST'];
		
		switch ($provider) {
			case 'twitter' :
				$url_params = array ('module' => 'inviter', 'controller' => 'oauth', 'action' => 'request', 'provider' => 'twitter' );
				$url = Zend_Controller_Front::getInstance ()->getRouter ()->assemble ( $url_params, 'default' );
				
				$config = array ('callbackUrl' => $host_url . $url, 'siteUrl' => 'http://twitter.com/oauth', 'consumerKey' => $settings->getSetting ( 'inviter.twitter.consumer.key', '' ), 'consumerSecret' => $settings->getSetting ( 'inviter.twitter.consumer.secret', '' ) );
				
				break;
			
			case 'linkedin' :
				$url_params = array ('module' => 'inviter', 'controller' => 'oauth', 'action' => 'request', 'provider' => 'linkedin' );
				$url = Zend_Controller_Front::getInstance ()->getRouter ()->assemble ( $url_params, 'default' );
				
				$config = array ('version' => '1.0', 'localUrl' => $host_url . $url, 'callbackUrl' => $host_url . $url, 'requestTokenUrl' => 'https://api.linkedin.com/uas/oauth/requestToken', 'userAuthorizationUrl' => 'https://api.linkedin.com/uas/oauth/authorize', 'accessTokenUrl' => 'https://api.linkedin.com/uas/oauth/accessToken', 'consumerKey' => $settings->getSetting ( 'inviter.linkedin.consumer.key', '' ), 'consumerSecret' => $settings->getSetting ( 'inviter.linkedin.consumer.secret', '' ) );
				
				break;
			
			case 'facebook' :
				$url_params = array ('module' => 'inviter', 'controller' => 'oauth', 'action' => 'request', 'provider' => 'facebook' );
				$url = Zend_Controller_Front::getInstance ()->getRouter ()->assemble ( $url_params, 'default' );
				
				$config = array ('version' => '1.0', 'localUrl' => $host_url . $url, 'callbackUrl' => $host_url . $url, 'consumerKey' => $settings->getSetting ( 'inviter.facebook.consumer.key', '' ), 'consumerSecret' => $settings->getSetting ( 'inviter.facebook.consumer.secret', '' ) );
				
				break;
			
			case 'gmail' :
				$url_params = array ('module' => 'inviter', 'controller' => 'oauth', 'action' => 'request', 'provider' => 'gmail' );
				$url = Zend_Controller_Front::getInstance ()->getRouter ()->assemble ( $url_params, 'default' );
				
				$config = array ('version' => '1.0', 'requestScheme' => Zend_Oauth::REQUEST_SCHEME_HEADER, 'callbackUrl' => $host_url . $url, 'requestTokenUrl' => 'https://www.google.com/accounts/OAuthGetRequestToken', 'userAuthorizationUrl' => 'https://www.google.com/accounts/OAuthAuthorizeToken', 'accessTokenUrl' => 'https://www.google.com/accounts/OAuthGetAccessToken', 'consumerKey' => $settings->getSetting ( 'inviter.gmail.consumer.key', '' ), 'consumerSecret' => $settings->getSetting ( 'inviter.gmail.consumer.secret', '' ) );
				
				break;
			
			default :
				break;
		}
		
		return $config;
	}
	
	public function checkIntegratedProvider($provider) {
		$settings = Engine_Api::_ ()->getApi ( 'settings', 'core' );
		$provider = strtolower ( str_replace ( '.', '_', $provider ) );
		
		switch ($provider) {
			case 'facebook' :
				$facebook = self::getFBInstance ();
				$status = $facebook->getAppId () ? true : false;
				break;
			
			case 'twitter' :
				$status = $settings->getSetting ( 'inviter.twitter.consumer.key', false ) ? true : false;
				break;
			
			case 'linkedin' :
				$status = $settings->getSetting ( 'inviter.linkedin.consumer.key', false ) ? true : false;
				break;
			
			case 'gmail' :
				$status = $settings->getSetting ( 'inviter.gmail.consumer.key', false ) ? true : false;
				break;
			
			default :
				$status = false;
				break;
		}
		
		return $status;
	}
	
	public function getContacts($token, $provider) {
		if (! $token) {
			return false;
		}
		
		$friends_data = array ('items' => array (), 'continue' => true, 'start' => 0 );
		
		if (APPLICATION_ENV == 'production') {
			
			if ($provider == 'facebook') {
				$cache_id = 'facebook_friends' . $token->getParam ( 'user_id' );
			} elseif ($provider == 'gmail') {
				$cache_id = 'inviter_' . $provider . '_friends_' . str_replace ( '@gmail.com', '', $token->getParam ( 'user_id' ) );
				$cache_id = str_replace ( '@', '_at_', $cache_id );
			} else {
				$cache_id = 'inviter_' . $provider . '_friends_' . $token->getParam ( 'user_id' );
			}
			
			$cache_id = str_replace ( '-', '_d_', $cache_id );
			$cache_id = str_replace ( '.', '_dt_', $cache_id );
			
			$cache = Engine_Cache::factory ();
			$_friends_data = $cache->load ( $cache_id );
			
			if ($_friends_data && is_array ( $_friends_data )) {
				$friends_data = $_friends_data;
				
				if (isset ( $friends_data ['continue'] ) && ! $friends_data ['continue']) {
					return $friends_data ['items'];
				}
			}
		}
		
		$limit_start = (isset ( $friends_data ['start'] ) && $friends_data ['start']) ? $friends_data ['start'] : 0;
		$limit_count = 100;
		
		switch ($provider) {
			
			case 'twitter' :
				$contact_ids = $this->getTwitterContactIds ( $token, $limit_start, $limit_count );
				$contact_arr = $this->getTwitterContacts ( $token, $contact_ids );
				break;
			
			case 'linkedin' :
				$contact_arr = $this->getLinkedInContacts ( $token, $limit_start, $limit_count );
				break;
			
			case 'facebook' :
				$contact_arr = $this->getFacebookContacts ( $token, $limit_start, $limit_count );
				break;
			
			case 'gmail' :
				$contact_arr = $this->getGMailContacts ( $token, $limit_start, $limit_count );
				break;
			
			default :
				$contact_arr = array ();
				break;
		}
		
		if ($contact_arr === false) {
			return $contact_arr;
		}
		
		$contacts = ($friends_data ['items']) ? $friends_data ['items'] : array ();
		foreach ( $contact_arr as $contact_id => $contact_info ) {
			$contacts [$contact_id] = $contact_info;
		}
		
		$friends_data = array ('items' => $contacts, 'start' => $limit_start + count ( $contact_arr ), 'continue' => (count ( $contact_arr ) == $limit_count) );
		
		if (APPLICATION_ENV == 'production') {
			$cache->save ( $friends_data, $cache_id );
			$cache->setLifetime ( 2 * 24 * 3600 ); // TODO SET RIGHT VALUE
		}
		
		return $contacts;
	}
	
	public function getTwitterContactIds($token, $start, $count) {
		$client = $token->getHttpClient ( $this->getProviderConfig ( 'twitter' ) );
		$client->setUri ( 'http://api.twitter.com/1/followers/ids.json' );
		$client->setMethod ( Zend_Http_Client::GET );
		$client->setParameterGet ( 'user_id', $token->getParam ( 'user_id' ) );
		
		/**
		 * @var Zend_Http_Response
		 */
		$response = $client->request ();
		$status = $response->getStatus ();
		
		if ($status != 200) {
			return false;
		}
		
		$follower_ids = Zend_Json::decode ( $response->getBody (), Zend_Json::TYPE_ARRAY );
		
		$contact_ids = array ();
		foreach ( $follower_ids as $index => $follower_id ) {
			if ($index < $start) {
				continue;
			}
			
			if ($index >= ($start + $count)) {
				break;
			}
			
			$contact_ids [] = $follower_id;
		}
		
		return $contact_ids;
	}
	
	public function getTwitterContacts($token, $contact_ids) {
		$contacts = array ();
		
		if (! $contact_ids) {
			return $contacts;
		}
		
		$contacts_str = implode ( ',', $contact_ids );
		
		$client = $token->getHttpClient ( $this->getProviderConfig ( 'twitter' ) );
		$client->setUri ( 'http://api.twitter.com/1/users/lookup.json' );
		$client->setMethod ( Zend_Http_Client::GET );
		$client->setParameterGet ( 'user_id', $contacts_str );
		$response = $client->request ();
		$status = $response->getStatus ();
		
		if ($status != 200) {
			return false;
		}
		
		$contact_arr = Zend_Json::decode ( $response->getBody () );
		foreach ( $contact_arr as $contact_info ) {
			$contacts [$contact_info ['id']] = array ('id' => $contact_info ['id'], 'email' => $contact_info ['screen_name'], 'profile_image_url' => $contact_info ['profile_image_url'], 'name' => $contact_info ['name'] );
		}
		
		return $contacts;
	}
	
	public function getLinkedInContacts($token, $start = 0, $count = 2) {
		$client = $token->getHttpClient ( $this->getProviderConfig ( 'linkedin' ) );
		$client->setUri ( 'http://api.linkedin.com/v1/people/~/connections:(id,first-name,last-name,picture-url,public-profile-url)' );
		$client->setMethod ( Zend_Http_Client::GET );
		$client->setParameterGet ( 'user_id', $token->getParam ( 'user_id' ) );
		$client->setParameterGet ( 'count', $count );
		$client->setParameterGet ( 'start', $start );
		$response = $client->request ();
		
		$status = $response->getStatus ();
		
		if ($status != 200) {
			return false;
		}
		
		$content = $response->getBody ();
		$xml = simplexml_load_string ( $content );
		
		$contacts = array ();
		foreach ( $xml->{'person'} as $person ) {
			$start ++;
			$contacts [$person->{'id'} . ''] = array ('id' => $person->{'id'} . '', 'nid' => $start, 'name' => $person->{'first-name'} . ' ' . $person->{'last-name'}, 'profile_image_url' => isset ( $person->{'picture-url'} ) ? $person->{'picture-url'} . '' : '', 'public_profile_url' => isset ( $person->{'public-profile-url'} ) ? $person->{'public-profile-url'} . '' : '' );
		}
		
		return $contacts;
	}
	
	public function getFacebookContacts($token, $start = 0, $count = 2) {
		$fql = "SELECT uid, name, profile_url, pic_square FROM user " . "WHERE uid IN (SELECT uid2 FROM friend WHERE uid1={$token->getParam('user_id')}) " . "LIMIT $start, $count";
		
		$facebook = self::getFBInstance ();
		
		try {
			$_contacts = $facebook->api ( array ('method' => 'fql.query', 'access_token' => $token->getParam ( 'oauth_token' ), 'query' => $fql ) );
		} catch ( Exception $e ) {
			return false;
		}
		
		$contacts = array ();
		foreach ( $_contacts as $friend_info ) {
			$contacts [$friend_info ['uid']] = $friend_info;
		}
		
		return $contacts;
	}
	
	public function getGMailContacts($token, $start = 0, $count = 2) {
		$start ++;
		
		$client = $token->getHttpClient ( $this->getProviderConfig ( 'gmail' ) );
		
		$client->setUri ( 'https://www.google.com/m8/feeds/contacts/default/thin' );
		$client->setMethod ( Zend_Http_Client::GET );
		$client->setParameterGet ( 'start-index', $start );
		$client->setParameterGet ( 'max-results', $count );
		
		$response = $client->request ();
		$status = $response->getStatus ();
		
		if ($status != 200) {
			return false;
		}
		
		$content = $response->getBody ();
		$xml = simplexml_load_string ( $content );
		
		$contacts = array ();
		foreach ( $xml->{'entry'} as $person ) {
			$gd_email = is_array ( $person->xpath ( 'gd:email' ) ) ? array_shift ( $person->xpath ( 'gd:email' ) ) : false;
			if (! $gd_email) {
				continue;
			}
			
			$email = $gd_email->attributes ()->{'address'} . '';
			
			if (! $email) {
				continue;
			}
			
			$name = (isset ( $person->{'title'} ) && $person->{'title'} . '') ? $person->{'title'} . '' : $email;
			
			$start ++;
			
			$contacts [$email] = array ('id' => $email, 'nid' => $start, 'name' => $name );
		}
		
		return $contacts;
	}
	
	public function getNoneMemberContacts($token, $provider, $count = 9) {
		$contacts = $this->getContacts ( $token, $provider );
		
		if ($contacts === false) {
			return $contacts;
		} elseif (! $contacts) {
			return $contacts;
		}
		
		$contact_ids = array_keys ( $contacts );
		
		// exclude already invited users
		$invitesTbl = Engine_Api::_ ()->getDbTable ( 'invites', 'inviter' );
		
		$invitesSel = $invitesTbl->select ()->setIntegrityCheck ( false )->from ( $invitesTbl->info ( 'name' ), array ('recipient' ) )->where ( 'provider = ?', $provider )->where ( 'new_user_id != ?', 0 );
		
		$invited_users = $invitesTbl->getAdapter ()->fetchCol ( $invitesSel );
		$contact_ids = array_diff ( $contact_ids, $invited_users );
		
		// exclude already joined users
		$tokensTbl = Engine_Api::_ ()->getDbTable ( 'tokens', 'inviter' );
		$tokensSel = $tokensTbl->select ()->setIntegrityCheck ( false )->from ( $tokensTbl->info ( 'name' ), array ('object_id' ) )->where ( 'provider = ?', $provider )->where ( 'user_id != ?', 0 );
		
		$members = $tokensTbl->getAdapter ()->fetchCol ( $tokensSel );
		$contact_ids = array_diff ( $contact_ids, $members );
		
		if ($provider == 'facebook') {
			// exclude already joined users
			$facebookTbl = Engine_Api::_ ()->getDbTable ( 'facebook', 'user' );
			$facebookSel = $facebookTbl->select ()->setIntegrityCheck ( false )->from ( $facebookTbl->info ( 'name' ), array ('facebook_uid' ) );
			
			$facebook_members = $facebookTbl->getAdapter ()->fetchCol ( $facebookSel );
			$contact_ids = array_diff ( $contact_ids, $facebook_members );
		} elseif ($provider == 'gmail') {
			$usersTbl = Engine_Api::_ ()->getItemTable ( 'user' );
			
			$already_members = array ();
			$contact_emails = array ();
			foreach ( $contact_ids as $index => $contact_id ) {
				$e_index = intval ( $index / 500 );
				
				if (! isset ( $contact_emails [$e_index] )) {
					$contact_emails [$e_index] = array ();
				}
				
				$contact_emails [$e_index] [] = $contact_id;
			}
			
			foreach ( $contact_emails as $emails ) {
				
				if (count ( $emails ) == 0) {
					continue;
				}
				
				$usersSel = $usersTbl->select ()->from ( array ('user' => $usersTbl->info ( 'name' ) ), array ('user.email' ) )->where ( 'user.email IN (?)', $emails );
				
				$member_list = $usersTbl->getAdapter ()->fetchCol ( $usersSel );
				
				if (! $member_list) {
					continue;
				}
				
				$already_members = ($already_members) ? $already_members : array ();
				$already_members = array_merge ( $already_members, $member_list );
			}
			
			$contact_ids = array_diff ( $contact_ids, $already_members );
		}
		
		if (! $contact_ids) {
			return array ();
		}
		
		shuffle ( $contact_ids );
		
		$none_members = array ();
		foreach ( $contact_ids as $contact_uid ) {
			$none_members [] = $contacts [$contact_uid];
			
			if (count ( $none_members ) == $count) {
				break;
			}
		}
		
		return $none_members;
	}
	
	public function getNoneFriendContacts($token, $provider, $count = 9) {
		$viewer_id = Engine_Api::_ ()->user ()->getViewer ()->getIdentity ();
		$contacts = $this->getContacts ( $token, $provider );
		
		if ($contacts === false) {
			return $contacts;
		} elseif (! $contacts) {
			return $contacts;
		}
		
		$contact_ids = array_keys ( $contacts );
		
		$usersTbl = Engine_Api::_ ()->getItemTable ( 'user' );
		$tokensTbl = Engine_Api::_ ()->getDbTable ( 'tokens', 'inviter' );
		$invitesTbl = Engine_Api::_ ()->getDbTable ( 'invites', 'inviter' );
		$membershipTbl = Engine_Api::_ ()->getDbtable ( 'membership', 'user' );
		
		if ($provider == 'facebook') {
			$facebookTbl = Engine_Api::_ ()->getDbTable ( 'facebook', 'user' );
			$object_uid_expr = new Zend_Db_Expr ( 'IF (invite.recipient, invite.recipient, IF (token.object_id, token.object_id, facebook.facebook_uid)) AS object_uid' );
			
			$select = $usersTbl->select ()->setIntegrityCheck ( false )->from ( array ('user' => $usersTbl->info ( 'name' ) ), array ('user.user_id', $object_uid_expr ) )->joinLeft ( array ('token' => $tokensTbl->info ( 'name' ) ), 'user.user_id = token.user_id AND token.provider = "' . $provider . '"', array () )->joinLeft ( array ('invite' => $invitesTbl->info ( 'name' ) ), 'user.user_id = invite.new_user_id AND invite.provider = "' . $provider . '"', array () )->joinLeft ( array ('facebook' => $facebookTbl->info ( 'name' ) ), 'user.user_id = facebook.user_id', array () )->joinLeft ( array ('friend' => $membershipTbl->info ( 'name' ) ), 'user.user_id = friend.user_id AND friend.resource_id = ' . $viewer_id, array () )->where ( 'NOT (ISNULL(invite.recipient) AND ISNULL(token.object_id) AND ISNULL(facebook.user_id))' )->where ( 'ISNULL(friend.resource_id)' )->where ( 'user.user_id != ?', $viewer_id );
		} else {
			$select = $usersTbl->select ()->setIntegrityCheck ( false )->from ( array ('user' => $usersTbl->info ( 'name' ) ), array ('user.user_id', new Zend_Db_Expr ( 'IF (invite.recipient, invite.recipient, token.object_id) AS object_uid' ) ) )->joinLeft ( array ('token' => $tokensTbl->info ( 'name' ) ), 'user.user_id = token.user_id AND token.provider = "' . $provider . '"', array () )->joinLeft ( array ('invite' => $invitesTbl->info ( 'name' ) ), 'user.user_id = invite.new_user_id AND invite.provider = "' . $provider . '"', array () )->joinLeft ( array ('friend' => $membershipTbl->info ( 'name' ) ), 'user.user_id = friend.user_id AND friend.resource_id = ' . $viewer_id, array () )->where ( 'NOT (ISNULL(invite.recipient) AND ISNULL(token.object_id))' )->where ( 'ISNULL(friend.resource_id)' )->where ( 'user.user_id != ?', $viewer_id );
		}
		
		$fb_members = $usersTbl->getAdapter ()->fetchPairs ( $select );
		
		if ($provider == 'gmail') {
			$contact_emails = array ();
			foreach ( $contact_ids as $index => $contact_id ) {
				$e_index = intval ( $index / 5 ); // @todo HEHE
				

				if (! isset ( $contact_emails [$e_index] )) {
					$contact_emails [$e_index] = array ();
				}
				
				$contact_emails [$e_index] [] = $contact_id;
			}
			
			foreach ( $contact_emails as $emails ) {
				
				if (count ( $emails ) == 0) {
					continue;
				}
				
				$usersSel = $usersTbl->select ()->from ( array ('user' => $usersTbl->info ( 'name' ) ), array ('user.user_id', 'user.email' ) )->where ( 'user.email IN (?)', $emails );
				
				$already_members = $usersTbl->getAdapter ()->fetchPairs ( $usersSel );
				
				if (! $already_members) {
					continue;
				}
				
				$already_members = ($already_members) ? $already_members : array ();
				foreach ( $already_members as $se_user_id => $email ) {
					$fb_members [$se_user_id] = $email;
				}
			}
		}
		
		$fb_none_friends = array ();
		$se_none_friend_ids = array ();
		foreach ( $fb_members as $se_user_id => $fb_member_id ) {
			if (! in_array ( $fb_member_id, $contact_ids )) {
				continue;
			}
			
			if (count ( $se_none_friend_ids ) >= $count) {
				break;
			}
			
			$fb_none_friends [$se_user_id] = new Inviter_Model_FacebookFriend ( $contacts [$fb_member_id], $provider );
			$se_none_friend_ids [] = $se_user_id;
		}
		
		if (count ( $se_none_friend_ids ) == 0) {
			return array ();
		}
		
		shuffle ( $se_none_friend_ids );
		
		return array ('fb_users' => $fb_none_friends, 'se_users' => Engine_Api::_ ()->getItemMulti ( 'user', $se_none_friend_ids ) );
	}
	
	public function getAlreadyFriendContacts($token, $provider, $count = 9) {
		$viewer_id = Engine_Api::_ ()->user ()->getViewer ()->getIdentity ();
		$contacts = $this->getContacts ( $token, $provider );
		
		if ($contacts === false) {
			return $contacts;
		} elseif (! $contacts) {
			return $contacts;
		}
		
		$contact_ids = array_keys ( $contacts );
		
		$usersTbl = Engine_Api::_ ()->getItemTable ( 'user' );
		$tokensTbl = Engine_Api::_ ()->getDbTable ( 'tokens', 'inviter' );
		$invitesTbl = Engine_Api::_ ()->getDbTable ( 'invites', 'inviter' );
		$membershipTbl = Engine_Api::_ ()->getDbtable ( 'membership', 'user' );
		
		if ($provider == 'facebook') {
			$facebookTbl = Engine_Api::_ ()->getDbTable ( 'facebook', 'user' );
			$object_uid_expr = new Zend_Db_Expr ( 'IF (invite.recipient, invite.recipient, IF (token.object_id, token.object_id, facebook.facebook_uid)) AS object_uid' );
			
			$select = $usersTbl->select ()->setIntegrityCheck ( false )->from ( array ('user' => $usersTbl->info ( 'name' ) ), array ('user.user_id', $object_uid_expr ) )->joinLeft ( array ('token' => $tokensTbl->info ( 'name' ) ), 'user.user_id = token.user_id AND token.provider = "' . $provider . '"', array () )->joinLeft ( array ('invite' => $invitesTbl->info ( 'name' ) ), 'user.user_id = invite.new_user_id AND invite.provider = "' . $provider . '"', array () )->joinLeft ( array ('facebook' => $facebookTbl->info ( 'name' ) ), 'user.user_id = facebook.user_id', array () )->joinLeft ( array ('friend' => $membershipTbl->info ( 'name' ) ), 'user.user_id = friend.user_id AND friend.resource_id = ' . $viewer_id, array () )->where ( 'NOT (ISNULL(invite.recipient) AND ISNULL(token.object_id) AND ISNULL(facebook.user_id))' )->where ( 'friend.active = ?', 1 );
		} else {
			$select = $usersTbl->select ()->setIntegrityCheck ( false )->from ( array ('user' => $usersTbl->info ( 'name' ) ), array ('user.user_id', new Zend_Db_Expr ( 'IF (invite.recipient, invite.recipient, token.object_id) AS object_uid' ) ) )->joinLeft ( array ('token' => $tokensTbl->info ( 'name' ) ), 'user.user_id = token.user_id AND token.provider = "' . $provider . '"', array () )->joinLeft ( array ('invite' => $invitesTbl->info ( 'name' ) ), 'user.user_id = invite.new_user_id AND invite.provider = "' . $provider . '"', array () )->joinLeft ( array ('friend' => $membershipTbl->info ( 'name' ) ), 'user.user_id = friend.user_id AND friend.resource_id = ' . $viewer_id, array () )->where ( 'NOT (ISNULL(invite.recipient) AND ISNULL(token.object_id))' )->where ( 'friend.active = ?', 1 );
		}
		
		$fb_members = $usersTbl->getAdapter ()->fetchPairs ( $select );
		
		$fb_already_friends = array ();
		$se_already_friend_ids = array ();
		foreach ( $fb_members as $se_user_id => $fb_member_id ) {
			if (! in_array ( $fb_member_id, $contact_ids )) {
				continue;
			}
			
			if (count ( $se_already_friend_ids ) >= $count) {
				break;
			}
			
			$fb_already_friends [$se_user_id] = new Inviter_Model_FacebookFriend ( $contacts [$fb_member_id], $provider );
			$se_already_friend_ids [] = $se_user_id;
		}
		
		if (count ( $se_already_friend_ids ) == 0) {
			return array ();
		}
		
		shuffle ( $se_already_friend_ids );
		
		return array ('fb_users' => $fb_already_friends, 'se_users' => Engine_Api::_ ()->getItemMulti ( 'user', $se_already_friend_ids ) );
	}
	
	public function sendInvites($token, $provider, $contact_ids) {
		if (! $token) {
			return 'Invalid token';
		}
		
		$viewer = Engine_Api::_ ()->user ()->getViewer ();
		$invitesTbl = Engine_Api::_ ()->getDbTable ( 'invites', 'inviter' );
		$contacts = $this->getContacts ( $token, $provider );
		
		if ($provider == 'linkedin' || $provider == 'gmail') {
			$contact_temp = array ();
			foreach ( $contacts as $uid => $info ) {
				if (in_array ( $info ['nid'], $contact_ids )) {
					$contact_temp [] = $uid;
				}
			}
			
			$contact_ids = $contact_temp;
		}
		
		switch ($provider) {
			case 'linkedin' :
				$result = $this->sendLinkedInInvites ( $token, $contact_ids );
				break;
			
			case 'twitter' :
				$result = $this->sendTwitterInvites ( $token, $contact_ids );
				break;
			
			case 'gmail' :
				$result = $this->sendGMailInvites ( $token, $contact_ids );
				break;
			
			default :
				$result = false;
				break;
		}
		
		if ($result === false) {
			return 'Service is not available now';
		}
		
		if ($provider == 'gmail') {
			return true;
		}
		
		$sent_date = new Zend_Db_Expr ( 'NOW()' );
		foreach ( $contact_ids as $contact_id ) {
			
			if (! isset ( $contacts [$contact_id] ) || ! isset ( $result [$contact_id] )) {
				continue;
			}
			
			$contact_info = $contacts [$contact_id];
			
			$invitesTbl->insertInvitation ( array ('user_id' => ( int ) $viewer->getIdentity (), 'sender' => $token->getParam ( 'user_id' ), 'recipient' => $contact_id, 'code' => $result [$contact_id], 'message' => '', 'sent_date' => $sent_date, 'provider' => $provider, 'recipient_name' => $contact_info ['name'] ) );
		}
		
		return true;
	}
	
	public function sendLinkedInInvites($token, $contact_ids) {
		if (! $token && ! $contact_ids) {
			return false;
		}
		
		$client = $token->getHttpClient ( $this->getProviderConfig ( 'linkedin' ) );
		
		$client->setUri ( 'http://api.linkedin.com/v1/people/~/mailbox' );
		$client->setMethod ( Zend_Http_Client::POST );
		
		$session = new Zend_Session_Namespace ( 'inviter' );
		$message = $session->__get ( 'message' );
		
		$translate = Zend_Registry::get ( 'Zend_Translate' );
		
		$subject = $translate->_ ( 'INVITER_You have received an invitation to join our social network.' );
		$body = $translate->_ ( 'INVITER_You have been invited by %1$s to join our social network. To join, please follow the link below: %2$s %3$s' );
		
		$sent = 0;
		$invite_codes = array ();
		foreach ( $contact_ids as $contact_id ) {
			$code = substr ( md5 ( rand ( 0, 999 ) . $contact_id ), 10, 7 );
			$url = $this->getInvitationUrl ( $code );
			
			$recipient = '    <recipient>
      <person path="/people/id=' . $contact_id . '" />
    </recipient>';
			
			$body = vsprintf ( $body, array ($token->getParam ( 'screen_name' ), $url, $message ) );
			
			$xml = <<<XML_MESSAGE
<?xml version="1.0" encoding="UTF-8"?>
<mailbox-item>
  <recipients>
    {$recipient}
  </recipients>
  <subject>{$subject}</subject>
  <body>{$body}</body>
</mailbox-item>
XML_MESSAGE;
			
			$client->setRawData ( $xml, 'text/xml' );
			$client->setHeaders ( 'Content-Type', 'text/xml' );
			$response = $client->request ();
			
			if ($response->getStatus () == 201) {
				$invite_codes [$contact_id] = $code;
				$sent ++;
			}
		}
		
		return $invite_codes;
	}
	
	public function sendTwitterInvites($token, $contact_ids) {
		if (! $token && ! $contact_ids) {
			return false;
		}
		
		$session = new Zend_Session_Namespace ( 'inviter' );
		$message = $session->__get ( 'message' );
		
		$sent = 0;
		$invite_codes = array ();
		foreach ( $contact_ids as $contact_id ) {
			$code = substr ( md5 ( rand ( 0, 999 ) . $contact_id ), 10, 7 );
			$url = $this->getInvitationUrl ( $code );
			$body = $message . ' ' . $url;
			
			$client = $token->getHttpClient ( $this->getProviderConfig ( 'twitter' ) );
			
			$client->setUri ( 'http://api.twitter.com/1/direct_messages/new.json' );
			$client->setMethod ( Zend_Http_Client::POST );
			$client->setParameterPost ( 'user_id', $contact_id );
			
			$client->setParameterPost ( 'text', $body );
			
			$response = $client->request ();
			
			if ($response->getStatus () == 200) {
				$invite_codes [$contact_id] = $code;
				$sent ++;
			}
		}
		
		return $invite_codes;
	}
	
	public function sendGMailInvites($token, $contact_ids) {
		if (! $token && ! $contact_ids) {
			return false;
		}
		
		$session = new Zend_Session_Namespace ( 'inviter' );
		$message = $session->__get ( 'message' );
		$invitesTbl = Engine_Api::_ ()->getDbtable ( 'invites', 'inviter' );
		
		$sent = 0;
		$provider = 'gmail';
		$sent_date = new Zend_Db_Expr ( 'NOW()' );
		
		$viewer = Engine_Api::_ ()->user ()->getViewer ();
		$contact_list = $this->getContacts ( $token, 'gmail' );
		
		foreach ( $contact_ids as $contact_id ) {
			if (! isset ( $contact_list [$contact_id] )) {
				continue;
			}
			
			do {
				$invite_code = substr ( md5 ( rand ( 0, 999 ) . $contact_id ), 10, 7 );
				$code_check = $invitesTbl->select ()->where ( 'code = ?', $invite_code );
			} while ( null !== $invitesTbl->fetchRow ( $code_check ) );
			
			$recipient = $contact_id;
			$recipient_name = $contact_list [$contact_id] ['name'];
			
			$inviteUrl = $this->getInvitationUrl ( $invite_code );
			$inviteUrl = '<a href="' . $inviteUrl . '">' . $inviteUrl . '</a>';
			
			$message = str_replace ( '[invite_url]', $inviteUrl, $message );
			
			// insert the invite into the database
			$db = Engine_Db_Table::getDefaultAdapter ();
			$db->beginTransaction ();
			try {
				$invitation = array ('user_id' => $viewer->getIdentity (), 'sender' => trim ( $token->getParam ( 'object_id' ) ), 'recipient' => trim ( $recipient ), 'recipient_name' => trim ( $recipient_name ), 'provider' => strtolower ( $provider ), 'code' => trim ( $invite_code ), 'sent_date' => $sent_date, 'message' => trim ( $message ) );
				
				if (! $invitesTbl->updateInvitation ( $invitation )) {
					$invitesTbl->insertInvitation ( $invitation );
				}
				
				$from_sender = ($viewer && $viewer->getIdentity () != 0) ? $viewer->getTitle () . "({$token->getParam('object_id')})" : $session->sender;
				
				$mail_settings = array ('from' => $from_sender, 'to' => $recipient, 'message' => $message, 'code' => $invite_code, 'link' => $inviteUrl );
				// send email
				Engine_Api::_ ()->getApi ( 'mail', 'core' )->sendSystem ( $recipient, 'inviter', $mail_settings );
				
				// mail sent, so commit
				$sent ++;
				$db->commit ();
			} catch ( Zend_Mail_Transport_Exception $e ) {
				$db->rollBack ();
			}
		}
		
		Engine_Api::_ ()->getDbtable ( 'statistics', 'inviter' )->increment ( 'inviter.sents', $sent );
		
		return $sent;
	}
	
	public function getInvitationUrl($code, $email = null) {
		$router = Zend_Controller_Front::getInstance ()->getRouter ();
		$host_url = (_ENGINE_SSL ? 'https://' : 'http://') . $_SERVER ['HTTP_HOST'];
		
		$params = array ('module' => 'inviter', 'controller' => 'signup', 'code' => $code );
		
		if ($email) {
			$params ['email'] = $email;
		}
		
		$invite_url = $host_url . $router->assemble ( $params, 'default', true );
		
		return $invite_url;
	}
	
	public function checkTwitterMessageLength($message) {
		if (! $message) {
			return true;
		}
		
		$code = substr ( md5 ( rand ( 0, 999 ) ), 10, 7 );
		$url = $this->getInvitationUrl ( $code );
		
		return (iconv_strlen ( $message . ' ' . $url, 'UTF-8' ) <= 140);
	}
	
	public function findContacts($provider) {
		$session = new Zend_Session_Namespace ( 'inviter' );
		
		if (! $session->__isset ( 'account_info' ) || ! $session->__get ( 'account_info' )) {
			return false;
		}
		
		$tokensTbl = Engine_Api::_ ()->getDbTable ( 'tokens', 'inviter' );
		
		$access_token_params = Zend_Json::decode ( $session->__get ( 'account_info' ), Zend_Json::TYPE_ARRAY );
		$token = $tokensTbl->getUserTokenByArray ( $access_token_params );
		
		if (! $token) {
			return false;
		}
		
		try {
			$contacts = $this->getNoneFriendContacts ( $token, $provider, 1000 );
		} catch ( Exception $e ) {
			$contacts = false;
		}
		
		if ($contacts && isset ( $contacts ['se_users'] ) && count ( $contacts ['se_users'] ) > 0) {
			$session->__set ( 'members', 1 );
		}
		
		try {
			$contacts = $this->getNoneMemberContacts ( $token, $provider, 1000 );
		} catch ( Exception $e ) {
			$contacts = false;
		}
		
		if ($contacts && count ( $contacts ) > 0) {
			$session->__set ( 'contacts', 1 );
		}
	}
}